home *** CD-ROM | disk | FTP | other *** search
/ Amiga Developer CD 2.1 / Amiga Developer CD v2.1.iso / Extras / Development / Example_Code_v37 / Libraries / Intuition / boopsi / textbclass.c < prev   
Encoding:
C/C++ Source or Header  |  1999-10-27  |  10.3 KB  |  432 lines

  1. /*** textbclass.c *******************************************************
  2.  *
  3.  * textbclass.c -- (repeating) command button gadget class
  4.  *
  5.  *  $Header:
  6.  *
  7.  *  Copyright (C) 1989-1999, Amiga, Inc.
  8.  *  All Rights Reserved
  9.  *
  10.  ****************************************************************************/
  11.  
  12. /*
  13. Copyright (c) 1989-1999 Amiga, Inc.
  14.  
  15. Executables based on this information may be used in software
  16. for Amiga computers. All other rights reserved.
  17. This information is provided "as is"; no warranties are made.
  18. All use is at your own risk, and no liability or responsibility
  19. is assumed.
  20. */
  21.  
  22. #include "sysall.h"
  23. #include <intuition/classes.h>
  24. #include <graphics/gfxmacros.h>
  25.  
  26. #define D(x)    ;
  27.  
  28. extern struct  IntuitionBase   *IntuitionBase;
  29. extern struct  GfxBase         *GfxBase;
  30. extern struct  Library         *UtilityBase;
  31.  
  32. /* transparent base class    */
  33. #define G(o)    ((struct Gadget *)(o))
  34.  
  35. /* jimm's peculiarities */
  36. #define testf(v,f) ((v) & (f))
  37. #define setf(v,f)    ((v) |= (f))
  38. #define clearf(v,f)    ((v) &= ~(f))
  39.  
  40. #define DH(x)    ;
  41.  
  42. /* this useful to convert a point structure to a 32 bit vanilla
  43.  * data type if you want to pass it via libcall to lattice.
  44.  * probably can fudge it some other way ...
  45.  */
  46. /* #define POINTLONG( pt )    (((pt).X<<16) + (pt).Y) */
  47.  
  48. #define POINTLONG( pt )    (*( (ULONG *)  &(pt) ))
  49.  
  50. /* private class    */
  51. #define PRIVATECLASS    TRUE
  52.  
  53. #if PRIVATECLASS
  54. #define MYCLASSID    (NULL)
  55. #else
  56. #define MYCLASSID    "textbclass"
  57. #endif
  58.  
  59. #define SUPERCLASSID    "buttongclass"
  60. extern struct IntuitionBase    *IntuitionBase;
  61.  
  62. struct TextBData {
  63.  
  64.     /* this is the offset of the contents, relative
  65.      * (0,0) of the gadget and its frame
  66.      */
  67.     struct {
  68.     UWORD    X;
  69.     UWORD    Y;
  70.     }        tbd_Offset;
  71.     ULONG    tbd_Flags;
  72. #define TBDF_USEFRAME    (1<<0)
  73. };
  74.  
  75.  
  76. Class    *
  77. initTextBClass()
  78. {
  79.     ULONG __saveds    dispatchTextB();
  80.     ULONG    hookEntry();
  81.     Class    *cl;
  82.     Class    *MakeClass();
  83.  
  84.     if ( cl =  MakeClass( MYCLASSID,
  85.         SUPERCLASSID, NULL,        /* superclass is public      */
  86.          sizeof( struct TextBData ),
  87.         0 ))
  88.     {
  89.     /* initialize the cl_Dispatcher Hook    */
  90.     cl->cl_Dispatcher.h_Entry = hookEntry;
  91.     cl->cl_Dispatcher.h_SubEntry = dispatchTextB;
  92.     cl->cl_Dispatcher.h_Data = (VOID *) 0xFACE;    /* unused */
  93.  
  94. #if !PRIVATECLASS
  95.     AddClass( cl );            /* make public and available    */
  96. #endif
  97.     }
  98.     return ( cl );
  99. }
  100.  
  101. freeTextBClass( cl )
  102. Class    *cl;
  103. {
  104.     return ( FreeClass( cl )  );
  105. }
  106.  
  107.  
  108. /*
  109.  * The main dispatcher for this class of custom gadgets
  110.  */
  111. ULONG __saveds
  112. dispatchTextB( cl, o, msg )
  113. Class   *cl;
  114. Object  *o;
  115. Msg     msg;
  116. {
  117.     ULONG        DoMethod();
  118.     Object          *newobj;
  119.     struct  RastPort    *rp;
  120.     int            refresh;
  121.     struct TextBData     *tbd;
  122.     ULONG        SetSuperAttrs();
  123.  
  124.     struct  RastPort    *ObtainGIRPort();
  125.  
  126.     tbd = INST_DATA( cl, o );
  127.  
  128.     switch ( msg->MethodID )
  129.     {
  130.     case OM_NEW:
  131.     D( kprintf("textbclass new\n") );
  132.     if ( newobj = (Object *) DSM( cl, o, msg ) )
  133.     {
  134.         tbd = INST_DATA( cl, newobj );    /* want it for newobject */
  135.  
  136.         /* frame our text, if any text ... */
  137.         if ( G(newobj)->GadgetText )
  138.         {
  139.         struct IBox    contents;
  140.         struct IBox    framebox;
  141.         struct DrawInfo    *drinfo;
  142.  
  143.         /* get the contents    */
  144.         drinfo = (struct DrawInfo *) GetTagData( GA_DRAWINFO, NULL,
  145.             ((struct opSet *) msg)->ops_AttrList );
  146.         getContentsExtent( newobj, drinfo, &contents );
  147.  
  148.         /* and if our image understands IM_FRAMEBOX    */
  149.         if ( DoMethod(  G(newobj)->GadgetRender, IM_FRAMEBOX,
  150.             &contents, &framebox, drinfo, 0 ) )
  151.         {
  152.             /* use the frame dimensions and offset    */
  153.             tbd->tbd_Flags |= TBDF_USEFRAME;
  154.             D( kprintf("call SSA to set width/height %lx/%lx\n",
  155.                 framebox.Width, framebox.Height ));
  156.  
  157.             SetSuperAttrs( cl, newobj,
  158.                 GA_WIDTH, framebox.Width,
  159.             GA_HEIGHT, framebox.Height,
  160.             TAG_END );
  161.             D( kprintf(" SetSuperAttrs returns, gadget Height %\n"));
  162.  
  163.             /* when we draw the frame at 0,0, we
  164.              * need to offset the text contents
  165.              * in the opposite direction.
  166.              */
  167.             tbd->tbd_Offset.X = -framebox.Left;
  168.             tbd->tbd_Offset.Y = -framebox.Top;
  169.         }
  170.         /* ZZZ: else just fail if not a frame? */
  171.         }
  172.  
  173.         /*  set attributes in general, which might force dims */
  174.         setTextBAttrs( cl, o, msg );
  175.     }
  176.     return ( (ULONG) newobj );
  177.  
  178.     case OM_UPDATE:
  179.     case OM_SET:
  180.     /* inherit atts, accumulated refresh    */
  181.     refresh = DSM( cl, o, msg );
  182.     refresh += setTextBAttrs( cl, o, msg );
  183.  
  184.     /* take responsibility here for refreshing visuals
  185.      * if I am the "true class."  It's sort of too bad
  186.      * that every class has to do this itself.
  187.      */
  188.     if ( refresh && ( OCLASS(o) == cl ) )
  189.     {
  190.         rp = ObtainGIRPort( ((struct opSet *)msg)->ops_GInfo );
  191.         if ( rp )
  192.         {
  193.         renderTextG( rp, ((struct opSet *)msg)->ops_GInfo, G(o), tbd,
  194.             GREDRAW_UPDATE );
  195.         }
  196.         ReleaseGIRPort( rp );
  197.         return ( 0 );        /* don't need refresh any more */
  198.     }
  199.     /* else */
  200.     return ( (ULONG) refresh );    /* return to subclass perhaps    */
  201.  
  202.     case GM_HITTEST:
  203.  
  204.  
  205. #if 1    /* use HITFRAME */
  206.     /* ask our frame if we have one  */
  207.     return ( DoMethod( G(o)->GadgetRender,
  208.         IM_HITFRAME,    /* even non-frames will understand this */
  209.         POINTLONG( ((struct gpHitTest *) msg)->gpht_Mouse ),
  210.         *((ULONG *) &G(o)->Width) ) );    /* trick    */
  211.  
  212. #else
  213.     return ( (ULONG) PointInImage( pointlong, G(o)->GadgetRender ) );
  214. #endif  /* use HITFRAME */
  215.  
  216.     case GM_RENDER:
  217.     renderTextG( ((struct gpRender *) msg)->gpr_RPort,
  218.         ((struct gpRender *) msg)->gpr_GInfo, o, tbd,
  219.         ((struct gpRender *)msg)->gpr_Redraw );
  220.     break;
  221.  
  222.     case OM_GET:    /* I'm not telling anyone about it yet    */
  223.     case GM_GOACTIVE:
  224.     case GM_GOINACTIVE:
  225.     case GM_HANDLEINPUT:    /* the big one    */
  226.     default:    /* let the superclass handle it */
  227.     return ( (ULONG) DSM( cl, o, msg ) );
  228.     }
  229.     return ( 0 );
  230. }
  231.  
  232.  
  233. renderTextG( rp, gi, o, tbd, redraw_mode )
  234. struct RastPort        *rp;
  235. struct GadgetInfo    *gi;
  236. Object            *o;
  237. struct TextBData     *tbd;
  238. {
  239.     int        state;
  240.  
  241.     if ( redraw_mode == GREDRAW_TOGGLE ) return;
  242.  
  243.     state = buttonDrawState( G(o), gi );
  244.  
  245.     /* draw frame    */
  246.     DoMethod( G(o)->GadgetRender, IM_DRAWFRAME, rp,
  247.                 *((ULONG *) &G(o)->LeftEdge),
  248.             state,
  249.             gi->gi_DrInfo,
  250.                 *((ULONG *) &G(o)->Width) );    /* frame dimensions */
  251.  
  252.     displayContents( rp, o, gi->gi_DrInfo,
  253.         G(o)->LeftEdge + tbd->tbd_Offset.X,
  254.         G(o)->TopEdge + tbd->tbd_Offset.Y, state );
  255. }
  256.  
  257. /*
  258.  * WARNING: this might change!
  259.  *
  260.  * returns image drawstate suitable for
  261.  * gadget active/border circumstances
  262.  */
  263.  
  264. #define ALLBORDERS (RIGHTBORDER+LEFTBORDER+TOPBORDER+BOTTOMBORDER)
  265. buttonDrawState( g, gi )
  266. struct Gadget        *g;
  267. struct GadgetInfo    *gi;
  268. {
  269.     if ( g && testf( g->Flags, SELECTED ) )
  270.     return ( IDS_SELECTED );
  271.  
  272.     if ( g && gi && gi->gi_Window &&
  273.     ! testf( gi->gi_Window->Flags, WINDOWACTIVE ) &&
  274.     ( testf( g->Activation, ALLBORDERS ) ||
  275.       testf( g->GadgetType, 0xF0 ) ) )    /* a "system" gadget */
  276.     {
  277.     if ( testf( g->Flags, SELECTED ) )
  278.         return ( IDS_INACTIVESELECTED );
  279.     /* else */
  280.         return ( IDS_INACTIVENORMAL );
  281.     }
  282.  
  283.     else if ( g && testf( g->Flags, SELECTED ) )
  284.         return (IDS_SELECTED );
  285.     /* else */
  286.     return ( IDS_NORMAL );
  287. }
  288.  
  289. setTextBAttrs( cl, o, msg )
  290. Class        *cl;
  291. Object        *o;
  292. struct opSet    *msg;
  293. {
  294.     struct TagItem    *NextTagItem();
  295.     struct TagItem    *tags = msg->ops_AttrList;
  296.     struct TagItem    *tag;
  297.     ULONG        tidata;
  298.     struct TextBData     *tbd;
  299.  
  300.     int            refresh = 0;
  301.     struct DrawInfo    *drinfo;
  302.     struct IBox        newframe;
  303.  
  304.     tbd = INST_DATA( cl, o );
  305.  
  306.     /* only interested in Width/Height fields */
  307.     newframe.Width = G(o)->Width;
  308.     newframe.Height = G(o)->Height;
  309.  
  310.     /* process rest */
  311.     while ( tag = NextTagItem( &tags ) )
  312.     {
  313.     tidata = tag->ti_Data;
  314.     switch ( tag->ti_Tag )
  315.     {
  316.  
  317.     /* if forced dimension change, then
  318.      * center text, recalc offsets using FRAMEF_SPECIFY
  319.      */
  320.      case GA_WIDTH:
  321.         refresh = 1;
  322.         newframe.Width = tidata;
  323.         break;
  324.      case GA_HEIGHT:
  325.         refresh = 1;
  326.         newframe.Height = tidata;
  327.         break;
  328.     /* could also reset for a new GA_IMAGE here, if
  329.      * you wanted
  330.      */
  331.     }
  332.     }
  333.  
  334.     /* fix up changes which require some work    */
  335.     if ( refresh )
  336.     {
  337.     /* get new offsets from the specified frame dimensions    */
  338.  
  339.     if ( tbd->tbd_Flags & TBDF_USEFRAME )
  340.     {
  341.         struct IBox    contents;
  342.  
  343.         /* really need DrawInfo, if layout change    */
  344.         drinfo = msg->ops_GInfo? msg->ops_GInfo->gi_DrInfo: NULL;
  345.  
  346.         /* override with tags version */
  347.         drinfo = (struct DrawInfo *) GetTagData( GA_DRAWINFO, drinfo, tags);
  348.  
  349.         /* get contents box again */
  350.         getContentsExtent( o, drinfo, &contents );
  351.  
  352.         DoMethod(  G(o)->GadgetRender, IM_FRAMEBOX, &contents,
  353.             &newframe, drinfo, FRAMEF_SPECIFY );
  354.  
  355.         tbd->tbd_Offset.X = -newframe.Left;
  356.         tbd->tbd_Offset.Y = -newframe.Top;
  357.     }
  358.  
  359.     /* superclass knows about the new dimensions, and I don't
  360.      * have any reason to disagree, so no need to
  361.      * override the values now.
  362.      */
  363.     }
  364.  
  365.     return ( refresh );
  366. }
  367.  
  368. /*
  369.  * This is going to be nifty.
  370.  * Right now, we'll use GadgetText as (UBYTE *),
  371.  * but we could conceivably code for this
  372.  * to be either simple text, or a pointer to
  373.  * a generic image Object which could be a text label,
  374.  * or glyph, or what have you.
  375.  *
  376.  * Then this class becomes the "button with label which is
  377.  * rendered by overdrawing some frame" class.
  378.  */
  379. getContentsExtent( o, drinfo, contents )
  380. Object        *o;
  381. struct DrawInfo    *drinfo;
  382. struct IBox    *contents;
  383. {
  384.     UBYTE    *label;
  385.     struct RastPort    rport;
  386.     struct TextExtent    textent;
  387.  
  388.     /* maybe look at some flags to handle other types of text someday */
  389.     if ( label = (UBYTE *) G(o)->GadgetText )
  390.     {
  391.     InitRastPort( &rport );
  392.     if ( drinfo && drinfo->dri_Font )
  393.     {
  394.         SetFont( &rport, drinfo->dri_Font );
  395.     }
  396.     TextExtent( &rport, label, strlen( label ), &textent );
  397.  
  398.     /* convert extent Rectangle to an IBox    */
  399.     contents->Left = textent.te_Extent.MinX;
  400.     contents->Top = textent.te_Extent.MinY;
  401.     contents->Width = textent.te_Extent.MaxX -  textent.te_Extent.MinX + 1;
  402.     contents->Height = textent.te_Extent.MaxY -  textent.te_Extent.MinY + 1;
  403.     }
  404.     else
  405.     {
  406.     contents->Left = contents->Top =
  407.         contents->Width = contents->Height = 0;
  408.     }
  409. }
  410.  
  411. /*
  412.  * show enclosed text label in correct color.
  413.  * always use textpen for now
  414.  */
  415. displayContents( rp, o, drinfo, offsetx, offsety, state )
  416. struct RastPort    *rp;
  417. Object        *o;
  418. struct DrawInfo    *drinfo;
  419. WORD        offsetx;
  420. WORD        offsety;
  421. {
  422.     UBYTE    *label;
  423.  
  424.     if ( label = (UBYTE *) G(o)->GadgetText )
  425.     {
  426.     SetDrMd( rp, JAM1 );
  427.     SetAPen( rp, drinfo->dri_Pens[ textPen ] );
  428.     Move( rp, offsetx, offsety );
  429.     Text( rp, label, strlen( label ) );
  430.     }
  431. }
  432.